package com.sxbdjw.situation.bdjw.webrtc;


import android.content.Context;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.NonNull;

import com.google.gson.Gson;
import com.sxbdjw.situation.bdjw.Config;

import org.webrtc.AudioSource;
import org.webrtc.AudioTrack;
import org.webrtc.CameraVideoCapturer;
import org.webrtc.DataChannel;
import org.webrtc.DefaultVideoDecoderFactory;
import org.webrtc.DefaultVideoEncoderFactory;
import org.webrtc.EglBase;
import org.webrtc.IceCandidate;
import org.webrtc.Logging;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
import org.webrtc.MediaStreamTrack;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.RtpReceiver;
import org.webrtc.RtpTransceiver;
import org.webrtc.SdpObserver;
import org.webrtc.SessionDescription;
import org.webrtc.SurfaceTextureHelper;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoDecoderFactory;
import org.webrtc.VideoEncoderFactory;
import org.webrtc.VideoSource;
import org.webrtc.VideoTrack;
import org.webrtc.audio.JavaAudioDeviceModule;
import org.webrtc.voiceengine.WebRtcAudioUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;


/**
 * Created by 玉念聿辉.
 * Use: WebRTC推拉流工具拉
 * Date: 2023/5/9
 * Time: 11:23
 */
public class WebRTCUtilYP implements PeerConnection.Observer, SdpObserver {

    private Context context;
    private EglBase eglBase = null;
    private String playUrl = null;
    private PeerConnection peerConnection = null;
    private SurfaceViewRenderer surfaceViewRenderer = null;
    private PeerConnectionFactory peerConnectionFactory = null;
    private AudioSource audioSource = null;
    private VideoSource videoSource = null;
    private AudioTrack localAudioTrack = null;
    private VideoTrack localVideoTrack = null;
    private CameraVideoCapturer captureAndroid = null;
    private SurfaceTextureHelper surfaceTextureHelper = null;
    private boolean isShowCamera = false;
    private boolean isPublish = false; //isPublish true为推流 false为拉流
    private Integer reConnCount = 0;


    private String TAG = "RtcActivity";
    private String VIDEO_TRACK_ID = "ARDAMSv0";
    private String AUDIO_TRACK_ID = "ARDAMSa0";
    private Integer VIDEO_RESOLUTION_WIDTH = 320;
    private Integer VIDEO_RESOLUTION_HEIGHT = 240;
    private Integer FPS = 30;
    private String AUDIO_ECHO_CANCELLATION_CONSTRAINT = "googEchoCancellation";
    private String AUDIO_AUTO_GAIN_CONTROL_CONSTRAINT = "googAutoGainControl";
    private String AUDIO_HIGH_PASS_FILTER_CONSTRAINT = "googHighpassFilter";
    private String AUDIO_NOISE_SUPPRESSION_CONSTRAINT = "googNoiseSuppression";




    public void create(EglBase eglBase, SurfaceViewRenderer surfaceViewRenderer, String playUrl) {
        create(eglBase, surfaceViewRenderer, false, playUrl);
    }

    public WebRTCUtilYP(Context context) {
        this.context = context.getApplicationContext();
    }

    public void create(EglBase eglBase, SurfaceViewRenderer surfaceViewRenderer, Boolean isPublish, String playUrl) {
        this.eglBase = eglBase;
        this.surfaceViewRenderer = surfaceViewRenderer;
        this.playUrl = playUrl;
        this.isPublish = isPublish;
        init();
    }

    public void create(EglBase eglBase, SurfaceViewRenderer surfaceViewRenderer, Boolean isPublish, Boolean isShowCamera, String playUrl) {
        this.eglBase = eglBase;
        this.surfaceViewRenderer = surfaceViewRenderer;
        this.playUrl = playUrl;
        this.isPublish = isPublish;
        this.isShowCamera = isShowCamera;
        init();
    }

    private void init() {

        // config 设置
        PeerConnection.RTCConfiguration rtcConfig = new PeerConnection.RTCConfiguration(new ArrayList<>());
        //关闭分辨率变换
        rtcConfig.enableCpuOveruseDetection = false;
        //修改模式 PlanB无法使用仅接收音视频的配置
        rtcConfig.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN;
        this.config = rtcConfig;


        peerConnectionFactory = getPeerConnectionFactory(this.context);
        // 这可以通过使用 PeerConnectionFactory 类并调用 createPeerConnection() 方法来创建WebRTC PeerConnection
        Logging.enableLogToDebugOutput(Logging.Severity.LS_NONE);
        peerConnection = peerConnectionFactory.createPeerConnection(config, this);

        //拉流
        if (!isPublish) {
            peerConnection.addTransceiver(MediaStreamTrack.MediaType.MEDIA_TYPE_AUDIO, new RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.RECV_ONLY));
            peerConnection.addTransceiver(MediaStreamTrack.MediaType.MEDIA_TYPE_VIDEO, new RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.RECV_ONLY));
        }
        //推流
        else {
            peerConnection.addTransceiver(MediaStreamTrack.MediaType.MEDIA_TYPE_AUDIO, new RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.SEND_ONLY));
            peerConnection.addTransceiver(MediaStreamTrack.MediaType.MEDIA_TYPE_VIDEO, new RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.SEND_ONLY));

            //设置回声去噪
            WebRtcAudioUtils.setWebRtcBasedAcousticEchoCanceler(true);
            WebRtcAudioUtils.setWebRtcBasedNoiseSuppressor(true);


            // 添加音频轨道
            audioSource = peerConnectionFactory.createAudioSource(createAudioConstraints());
            localAudioTrack = peerConnectionFactory.createAudioTrack(AUDIO_TRACK_ID, audioSource);
            localAudioTrack.setEnabled(true);
            peerConnection.addTrack(localAudioTrack);

            //添加视频轨道
            if (isShowCamera) {
                captureAndroid = CameraUtil.createVideoCapture(context);
                surfaceTextureHelper = SurfaceTextureHelper.create("CameraThread", eglBase.getEglBaseContext());
                videoSource = peerConnectionFactory.createVideoSource(false);
                captureAndroid.initialize(surfaceTextureHelper, context, videoSource.getCapturerObserver());
                captureAndroid.startCapture(VIDEO_RESOLUTION_WIDTH, VIDEO_RESOLUTION_HEIGHT, FPS);
                localVideoTrack = peerConnectionFactory.createVideoTrack(VIDEO_TRACK_ID, videoSource);
                localVideoTrack.setEnabled(true);
                if (surfaceViewRenderer != null) {
                    // 初始化
                    ProxyVideoSink videoSink = new ProxyVideoSink();
                    videoSink.setTarget(surfaceViewRenderer);
                    localVideoTrack.addSink(videoSink);
                }
                peerConnection.addTrack(localVideoTrack);
            }
        }
        peerConnection.createOffer(this, new MediaConstraints());
    }

    /**
     * 切换前后摄像头
     */
    public void changeVideoCapturer() {
        CameraVideoCapturer cameraVideoCapturer = captureAndroid;
        cameraVideoCapturer.switchCamera(null);
    }

    /**
     * 是否打开麦克风
     * @param flag
     */
    public void changeSpeak(boolean flag) {
        localAudioTrack.setEnabled(flag);
    }


    public void destroy() {

        if (peerConnection != null) {
            peerConnection.dispose();
            peerConnection = null;
        }
        if (surfaceTextureHelper != null) {
            surfaceTextureHelper.dispose();
            surfaceTextureHelper = null;
        }
        if (captureAndroid != null) {
            captureAndroid.dispose();
            captureAndroid = null;
        }

        if (localAudioTrack !=null){
            localAudioTrack.dispose();
            localAudioTrack=null;
        }

        if (surfaceViewRenderer != null) {
            surfaceViewRenderer.clearImage();
        }
        if (peerConnectionFactory != null) {
            peerConnectionFactory.dispose();
            peerConnectionFactory = null;
        }
    }

    /**
     * 配置音频参数
     *
     * @return
     */
    private MediaConstraints createAudioConstraints() {
        MediaConstraints audioConstraints = new MediaConstraints();
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair(AUDIO_ECHO_CANCELLATION_CONSTRAINT, "true"));
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair(AUDIO_AUTO_GAIN_CONTROL_CONSTRAINT, "false"));
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair(AUDIO_HIGH_PASS_FILTER_CONSTRAINT, "false"));
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair(AUDIO_NOISE_SUPPRESSION_CONSTRAINT, "true"));
        return audioConstraints;
    }

    /**
     * 交换sdp
     */
    private void openWebRtc(String sdp) {

        reConnCount++;
        OkHttpClient client = new OkHttpClient.Builder().connectTimeout(60, TimeUnit.SECONDS).build();
        String json = "";
//        try {
//            JSONObject jsonObject = new JSONObject();
//            jsonObject.put("sdp", sdp);
//            jsonObject.put("streamurl", Config.STREAM_URL_PREFIX + playUrl);
//
//            Log.d(TAG,"===========地址： " + Config.STREAM_URL_PREFIX + playUrl);
//
//            json = jsonObject.toString();
//        } catch (Exception e) {
//            Log.e(TAG, e.getMessage());
//        }
        String url  = Config.SRS_URL + "/index/api/webrtc?type=push&app=live&stream=" + playUrl;
        if (!isPublish){
            url  =Config.SRS_URL + "/index/api/webrtc?type=play&app=live&stream=" + playUrl;
        }
        Log.d(TAG,"===========地址： " + url);
        MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
        RequestBody body = RequestBody.create(mediaType, sdp);
        Log.d(TAG,"===========body： " + sdp);

        Request request = new Request.Builder().url(url).post(body).addHeader("Content-Type", "application/json").build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                Log.e(TAG, "交换sdp reConnCount:$reConnCount  异常: ${e.message}");

            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                String result = response.body().string();
                Gson gson = new Gson();

                try {
                    SdpBean sdpBean = gson.fromJson(result, SdpBean.class);
                    if (sdpBean != null && !TextUtils.isEmpty(sdpBean.sdp)) {
                        if (sdpBean.code == 400) {
                            Log.e(TAG, "交换sdp 400");
                        } else {
                            reConnCount = 0;
                            setRemoteSdp(sdpBean.sdp);
                        }
                    }
                }catch (Exception e){

                    Log.e(TAG, result);
                }
            }
        });

    }

    private void setRemoteSdp(String sdp) {
        if (peerConnection != null) {
            SessionDescription remoteSpd = new SessionDescription(SessionDescription.Type.ANSWER, sdp);
            peerConnection.setRemoteDescription(this, remoteSpd);
        }
    }


    /**
     * 获取 PeerConnectionFactory
     */
    private PeerConnectionFactory getPeerConnectionFactory(Context context) {
        PeerConnectionFactory.InitializationOptions initializationOptions = PeerConnectionFactory.InitializationOptions.builder(context).setEnableInternalTracer(true).setFieldTrials("WebRTC-H264HighProfile/Enabled/").createInitializationOptions();
        PeerConnectionFactory.initialize(initializationOptions);

        // 2. 设置编解码方式：默认方法
        VideoEncoderFactory encoderFactory = new DefaultVideoEncoderFactory(eglBase.getEglBaseContext(), false, true);
        VideoDecoderFactory decoderFactory = new DefaultVideoDecoderFactory(eglBase.getEglBaseContext());

        // 构造Factory
        PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions.builder(context).createInitializationOptions());
        return PeerConnectionFactory.builder()
                .setOptions(new PeerConnectionFactory.Options())
                .setAudioDeviceModule(JavaAudioDeviceModule.builder(context).createAudioDeviceModule())
                .setVideoEncoderFactory(encoderFactory)
                .setVideoDecoderFactory(decoderFactory)
                .createPeerConnectionFactory();
    }

    //修改模式 PlanB无法使用仅接收音视频的配置
    private PeerConnection.RTCConfiguration config;


    @Override
    public void onCreateSuccess(SessionDescription sdp) {
        if (sdp.type == SessionDescription.Type.OFFER) {
            //设置setLocalDescription offer返回sdp
            peerConnection.setLocalDescription(this, sdp);
            if (!TextUtils.isEmpty(sdp.description)) {
                reConnCount = 0;
                openWebRtc(sdp.description);
            }
        }
    }

    @Override
    public void onSetSuccess() {

    }

    @Override
    public void onCreateFailure(String s) {

    }

    @Override
    public void onSetFailure(String s) {

    }


    @Override
    public void onSignalingChange(PeerConnection.SignalingState signalingState) {

    }

    @Override
    public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {

    }

    @Override
    public void onIceConnectionReceivingChange(boolean b) {

    }

    @Override
    public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {

    }

    @Override
    public void onIceCandidate(IceCandidate iceCandidate) {
        peerConnection.addIceCandidate(iceCandidate);
    }

    @Override
    public void onIceCandidatesRemoved(IceCandidate[] iceCandidates) {
        peerConnection.removeIceCandidates(iceCandidates);
    }

    @Override
    public void onAddStream(MediaStream mediaStream) {

    }

    @Override
    public void onRemoveStream(MediaStream mediaStream) {

    }

    @Override
    public void onDataChannel(DataChannel dataChannel) {

    }

    @Override
    public void onRenegotiationNeeded() {

    }

    @Override
    public void onAddTrack(RtpReceiver receiver, MediaStream[] mediaStreams) {
        MediaStreamTrack track = receiver.track();
        if (track instanceof VideoTrack) {
            VideoTrack remoteVideoTrack = (VideoTrack) track;
            remoteVideoTrack.setEnabled(true);
            if (surfaceViewRenderer != null && isShowCamera) {
                ProxyVideoSink videoSink = new ProxyVideoSink();
                videoSink.setTarget(surfaceViewRenderer);
                remoteVideoTrack.addSink(videoSink);
            }
        }
    }


}